// this is aliased in webpack config based on server/client build
import { createAPI } from 'create-api' // 客户端和服务端不同，在webpack文件中配置的

const logRequests = !!process.env.DEBUG_API

const api = createAPI({ // google 的 firebase服务
  version: '/v0',
  config: {
    databaseURL: 'https://hacker-news.firebaseio.com'
  }
})

// warm the front page cache every 15 min
// make sure to do this only once across all requests
// 每15分钟预热一次首页缓存
// 确保在所有请求中只执行一次
if (api.onServer) { // 服务端才会执行
  warmCache()
}

// 恰巧在create-api-server.js中使用的LRU缓存api.cachedItems，也是15分钟
// 在api.cachedItems缓存没有过期前，不会再次请求数据，而是直接用
// 过期后，这里会重新请求数据
function warmCache () {
  fetchItems((api.cachedIds.top || []).slice(0, 30))
  setTimeout(warmCache, 1000 * 60 * 15)
}
// TODO:api.cachedItems 和 api.cachedIds缓存都是服务端用的，客户端没有设置
// child是`${type}stories`或者`item/${id}`或者`user/${id}`
function fetch (child) {
  logRequests && console.log(`fetching ${child}...`)
  const cache = api.cachedItems // 用了LRU缓存，返回的应该是一个类似MAP的数据结构
  if (cache && cache.has(child)) {
    logRequests && console.log(`cache hit for ${child}.`)
    return Promise.resolve(cache.get(child))
  } else {
    return new Promise((resolve, reject) => {
      api.child(child).once('value', snapshot => {
        const val = snapshot.val()
        // mark the timestamp when this item is cached
        if (val) val.__lastUpdated = Date.now()
        cache && cache.set(child, val)
        logRequests && console.log(`fetched ${child}.`)
        resolve(val)
      }, reject)
    })
  }
}

// 两层缓存，一层是LRU缓存 api.cachedItems，一层是 api.cachedIds
export function fetchIdsByType (type) {
  // api.cachedIds是服务端调用createAPI的时候已经在内部预取了各个type的id列表数据
  return api.cachedIds && api.cachedIds[type]
    ? Promise.resolve(api.cachedIds[type])
    : fetch(`${type}stories`)
}

export function fetchItem (id) {
  return fetch(`item/${id}`)
}

export function fetchItems (ids) {
  return Promise.all(ids.map(id => fetchItem(id)))
}

export function fetchUser (id) {
  return fetch(`user/${id}`)
}

// 用于给客户端组件监听firebase的数据变化(挂载组件的beforeMount钩子上)
// 按照上面fetch中api的用法，api.child应该是发出一个请求
// 调用之后会暴露出几个方法，once/on/off，off应该是可以中断请求
export function watchList (type, cb) {
  let first = true
  const ref = api.child(`${type}stories`) // 这玩意返回ids列表（一系列数据的id组成的列表）
  const handler = snapshot => {
    if (first) {
      // 第一次的数据不需要，因为已经在服务端渲染过了，使用服务端初始的store的数据即可
      first = false
    } else {
      cb(snapshot.val())
    }
  }
  // on监听，如果某个类型的列表数据有变化，立马更新，
  // 因为这里监听的某个类型的id列表数据的变化，所以更新该类型的id列表数据，此时活跃id列表跟着变
  // 然后再调用dispatch('ENSURE_ACTIVE_ITEMS')方法更新活跃id对应的item列表...
  ref.on('value', handler)
  return () => {
    ref.off('value', handler) // 组件销毁的时候注销数据变化监听
  }
}
